﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Moki.Tests.Model;
using Moki;
using Moki.State;

namespace Moki.Specification
{
    [TestFixture]
    public class CustomArgsSpec
    {
        [TearDown]
        public void TearDown()
        {
            Mock.CleanUp();
        }

        [Test]
        public void Arg_any_test()
        {
            var test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.NeedSomeArguments(1, Arg.Any<string>(), true)).Returns(100);

            Assert.AreEqual(100, test.NeedSomeArguments(1,"abc", true));
            Assert.AreEqual(100, test.NeedSomeArguments(1, "", true));
        }

        [Test]
        public void Arg_one_match_test()
        {
            var test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.NeedSomeArguments(1, Arg.Matches<string>(s => s.Length < 3), true)).Returns(100);

            Assert.AreEqual(100, test.NeedSomeArguments(1, "", true));
            Assert.AreEqual(100, test.NeedSomeArguments(1, "ab", true));
            Assert.AreEqual(0,  test.NeedSomeArguments(1, "abcd", true));
        }

        [Test]
        public void Arg_two_matches_test()
        {
            var test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.NeedSomeArguments(1, Arg.Matches<string>(s => s.Length < 3), true)).Returns(100);
            Mock.WhenCalled(() => test.NeedSomeArguments(1, Arg.Matches<string>(s => s.Length > 3), true)).Returns(200);

            Assert.AreEqual(100, test.NeedSomeArguments(1, "", true));
            Assert.AreEqual(100, test.NeedSomeArguments(1, "ab", true));
            Assert.AreEqual(200, test.NeedSomeArguments(1, "abcd", true));
        }

        [Test]
        public void Arg_second_matches_should_not_match_previous_stub()
        {
            var test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.NeedSomeArguments(Arg.Matches<int>(i => i > 0), "aa", true)).Returns(100);
            // This should create new stub context
            Mock.WhenCalled(() => test.NeedSomeArguments(Arg.Matches<int>(i => i <= 0), "aa", true)).Returns(200);

            Assert.AreEqual(200, test.NeedSomeArguments(0, "aa", true));
            Assert.AreEqual(100, test.NeedSomeArguments(1, "aa", true));
           
        }

        [Test]
        public void Arg_matches_covers_others_consecutive_stubs()
        {
            var test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.NeedSomeArguments(Arg.Matches<int>(i => i >= 0), "aa", true)).Returns(100);
            Mock.WhenCalled(() => test.NeedSomeArguments(0, "aa", true)).Returns(200);

            Assert.AreEqual(100, test.NeedSomeArguments(0, "aa", true));

        }

        [Test]
        public void Arg_value_covers_other_sonsecutive_stubs()
        {
            var test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.NeedSomeArguments(0, "aa", true)).Returns(200);
            Mock.WhenCalled(() => test.NeedSomeArguments(Arg.Matches<int>(i => i >= 0), "aa", true)).Returns(100);
         
            Assert.AreEqual(200, test.NeedSomeArguments(0, "aa", true));

        }

        [Test]
        public void Arg_any_with_when_set()
        {
            ITests test = Mock.Create<ITests>();
            int i = 0;

            Mock.WhenSet(() => test.Id, Arg.Any<int>()).Callback(() => i++);

            test.Id = 1;
            test.Id = 2;
            test.Id = 3;

            Assert.AreEqual(3, i);


        }

      
    }
}
